import { utilities } from '@cornerstonejs/core';
import type { ContourSegmentationAnnotation } from '../../types';
import { addAnnotation, getAnnotation } from '../../stateManagement';
import { getViewportAssociatedToSegmentation } from '../../stateManagement/segmentation/utilities/getViewportAssociatedToSegmentation';
import { getToolGroupForViewport } from '../../store/ToolGroupManager';
import { getAnnotationsUIDMapFromSegmentation } from '../../stateManagement/segmentation/utilities/getAnnotationsUIDMapFromSegmentation';

/**
 * Creates a deep copy of a contour segmentation annotation, assigning it to a new segmentation and segment index.
 * Copies polyline and handle points, and generates a new annotation UID.
 *
 * @param annotation - The annotation to copy
 * @param segmentationId - The target segmentation ID
 * @param segmentIndex - The target segment index
 * @returns A new ContourSegmentationAnnotation object
 */
export function copyAnnotation(
  annotation: ContourSegmentationAnnotation,
  segmentationId: string,
  segmentIndex: number
): ContourSegmentationAnnotation {
  const newAnnotation: ContourSegmentationAnnotation = {
    annotationUID: utilities.uuidv4(),
    data: {
      contour: {
        closed: true,
        polyline: [],
      },
      segmentation: {
        segmentationId,
        segmentIndex,
      },
      handles: {},
    },
    handles: {},
    highlighted: false,
    autoGenerated: false,
    invalidated: false,
    isLocked: false,
    isVisible: true,
    metadata: {
      ...annotation.metadata,
      toolName: annotation.metadata.toolName,
    },
  };
  newAnnotation.data.segmentation.segmentationId = segmentationId;
  newAnnotation.data.segmentation.segmentIndex = segmentIndex;

  // Copy specific attributes
  if (annotation.data.contour?.polyline) {
    newAnnotation.data.contour.polyline = [...annotation.data.contour.polyline];
  }

  if (annotation.data.handles?.points) {
    newAnnotation.data.handles.points = annotation.data.handles.points.map(
      (point) => [...point]
    );
  }

  return newAnnotation;
}

/**
 * Copies all contour annotations from a segment in one segmentation to a segment in another segmentation.
 * Handles copying of child annotations and spline objects if present.
 *
 * @param segmentationId - Source segmentation ID
 * @param segmentIndex - Source segment index
 * @param targetSegmentationId - Target segmentation ID
 * @param targetSegmentIndex - Target segment index
 */
export function copyContourSegment(
  segmentationId: string,
  segmentIndex: number,
  targetSegmentationId: string,
  targetSegmentIndex: number
) {
  const annotationUIDsMap =
    getAnnotationsUIDMapFromSegmentation(segmentationId);
  const targetAnnotationUIDsMap =
    getAnnotationsUIDMapFromSegmentation(targetSegmentationId);
  if (!annotationUIDsMap || !targetAnnotationUIDsMap) {
    return;
  }

  if (!annotationUIDsMap?.has(segmentIndex)) {
    return;
  }

  const annotationUIDs = annotationUIDsMap.get(segmentIndex);

  const viewport = getViewportAssociatedToSegmentation(targetSegmentationId);
  if (!viewport) {
    return;
  }
  const toolGroup = getToolGroupForViewport(viewport.id);

  const copyContourAnnotation = (annotation: ContourSegmentationAnnotation) => {
    const newAnnotation = copyAnnotation(
      annotation,
      targetSegmentationId,
      targetSegmentIndex
    );
    if (toolGroup) {
      const instance = toolGroup.getToolInstance(annotation.metadata.toolName);
      if (instance) {
        // Properly test if the function isSplineAnnotation exists in instance
        if (
          typeof instance.isSplineAnnotation === 'function' &&
          instance.isSplineAnnotation(annotation)
        ) {
          instance.createSplineObjectFromType(
            newAnnotation,
            (annotation.data.spline as { type: string }).type
          );
        }
      }
    }
    addAnnotation(newAnnotation, viewport.element);
    newAnnotationsUID.add(newAnnotation.annotationUID);
    return newAnnotation;
  };

  const newAnnotationsUID = new Set<string>();
  for (const annotationUID of annotationUIDs) {
    const annotation = getAnnotation(
      annotationUID
    ) as ContourSegmentationAnnotation;
    const newAnnotation = copyContourAnnotation(annotation);
    if (annotation?.childAnnotationUIDs) {
      newAnnotation.childAnnotationUIDs = [];
      for (const childAnnotationUID of annotation.childAnnotationUIDs) {
        const childAnnotation = getAnnotation(
          childAnnotationUID
        ) as ContourSegmentationAnnotation;
        const newChildAnnotation = copyContourAnnotation(childAnnotation);
        newChildAnnotation.parentAnnotationUID = newAnnotation.annotationUID;
        newAnnotation.childAnnotationUIDs.push(
          newChildAnnotation.annotationUID
        );
      }
    }
  }

  targetAnnotationUIDsMap.set(targetSegmentIndex, newAnnotationsUID);
}
